/*
 * CallInstruction.cpp
 *
 *  Created on: 17/nov/2010
 *      Author: computer
 */

#include "CallInstruction.h"
#include "Lambda.h"
#include <sstream>

namespace TreeExpression {

CallInstruction::CallInstruction(const std::string& _name) : FlowExpression(), Expression_CRTP<CallInstruction>(), name(_name) { }

CallInstruction::CallInstruction(const CallInstruction& copy) : Expression(copy), FlowExpression(copy), Expression_CRTP<CallInstruction>(copy), name(copy.name) { }

CallInstruction::~CallInstruction() { }

AutoPointer<Expression> CallInstruction::eval(CopyPointer<Context>& context) {
	std::list< AutoPointer<Expression> > listFunction = context->searchDeclarationInGlobal(name);
	if (listFunction.empty()) {
		AutoPointer<Expression> ris(new CallInstruction(*this));
		ris->evalTree(context);
		return ris;
	}
	else {
		AutoPointer<Expression> function(NULL);
		int call = 0;
		std::list< AutoPointer<Expression> >::iterator i;
		this->evalTree(context);
		for (i = listFunction.begin(); i != listFunction.end(); ++i) {
			Functor* localFunction = dynamic_cast<Functor*>(i->get());
			int localCall = localFunction->match(this->getSon());//TODO memory
			if (localCall > call) {
				call = localCall;
				function = *i;
			}
		}
		if (function.isNull()) {
			AutoPointer<Expression> ris(new CallInstruction(*this));
			return ris;
		}
		else {
			if (this->hasSon()) function->setSon(this->getSon());//load the parameter
			AutoPointer<Expression> ris = function->eval(context);//call the function
			ris->addLeaf(this->getLeaf());//copy the other tree expression before return
			return ris;//return the result
		}
	}
}

std::string CallInstruction::toString() const {
	std::ostringstream oss;
	oss << name << "(";
	if (this->hasSon()) {
		oss << this->getSon()->toString();
		AutoPointer<Expression> param = this->getSon();
		while (param->hasLeaf()) {
			oss << ", " << param->getLeaf()->toString();
			param = param->getLeaf();
		}
		oss << ")";
		return oss.str();
	}
	else {
		oss << ")";
		return oss.str();
	}
}

}

